//===-- python_test_ops.td - Python test Op definitions ----*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef PYTHON_TEST_OPS
#define PYTHON_TEST_OPS

include "mlir/IR/AttrTypeBase.td"
include "mlir/Bindings/Python/Attributes.td"
include "mlir/IR/OpBase.td"
include "mlir/Interfaces/InferTypeOpInterface.td"

def Python_Test_Dialect : Dialect {
  let name = "python_test";
  let cppNamespace = "python_test";

  let useDefaultTypePrinterParser = 1;
  let useDefaultAttributePrinterParser = 1;
}

class TestType<string name, string typeMnemonic>
    : TypeDef<Python_Test_Dialect, name> {
  let mnemonic = typeMnemonic;
}

class TestAttr<string name, string attrMnemonic>
    : AttrDef<Python_Test_Dialect, name> {
  let mnemonic = attrMnemonic;
}

class TestOp<string mnemonic, list<Trait> traits = []>
    : Op<Python_Test_Dialect, mnemonic, traits>;

//===----------------------------------------------------------------------===//
// Type definitions.
//===----------------------------------------------------------------------===//

def TestType : TestType<"TestType", "test_type">;

//===----------------------------------------------------------------------===//
// Attribute definitions.
//===----------------------------------------------------------------------===//

def TestAttr : TestAttr<"TestAttr", "test_attr">;

//===----------------------------------------------------------------------===//
// Operation definitions.
//===----------------------------------------------------------------------===//

def AttributedOp : TestOp<"attributed_op"> {
  let arguments = (ins I32Attr:$mandatory_i32,
                   OptionalAttr<I32Attr>:$optional_i32,
                   UnitAttr:$unit);
}

def PropertyOp : TestOp<"property_op"> {
  let arguments = (ins I32Attr:$property,
                   I32:$idx);
}

def DummyOp : TestOp<"dummy_op"> {
}

def InferResultsOp : TestOp<"infer_results_op", [InferTypeOpInterface]> {
  let arguments = (ins);
  let results = (outs AnyInteger:$single, AnyInteger:$doubled);

  let extraClassDeclaration = [{
    static ::mlir::LogicalResult inferReturnTypes(
      ::mlir::MLIRContext *context, ::std::optional<::mlir::Location> location,
      ::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
      ::mlir::RegionRange regions,
      ::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
      ::mlir::Builder b(context);
      inferredReturnTypes.push_back(b.getI32Type());
      inferredReturnTypes.push_back(b.getI64Type());
      return ::mlir::success();
    }
  }];
}

// If all result types are buildable, the InferTypeOpInterface is implied and is
// autogenerated by C++ ODS.
def InferResultsImpliedOp : TestOp<"infer_results_implied_op"> {
  let results = (outs I32:$integer, F64:$flt, Index:$index);
}

def SameOperandAndResultTypeOp : TestOp<"same_operand_and_result_type_op",
                                        [SameOperandsAndResultType]> {
  let arguments = (ins Variadic<AnyType>);
  let results = (outs AnyType:$one, AnyType:$two);
}

def FirstAttrDeriveTypeAttrOp : TestOp<"first_attr_derive_type_attr_op",
                               [FirstAttrDerivedResultType]> {
  let arguments = (ins AnyType:$input, TypeAttr:$type);
  let results = (outs AnyType:$one, AnyType:$two);
}

def FirstAttrDeriveAttrOp : TestOp<"first_attr_derive_attr_op",
                               [FirstAttrDerivedResultType]> {
  let arguments = (ins AnyAttr:$iattr);
  let results = (outs AnyType:$one, AnyType:$two, AnyType:$three);
}

def OptionalOperandOp : TestOp<"optional_operand_op"> {
  let arguments = (ins Optional<AnyType>:$input);
  let results = (outs I32:$result);
}

#endif // PYTHON_TEST_OPS
